﻿bob.ns.setNs('bob.prop.event', {

    //v.2
    ///derives from bob.prop.Property
    NotifierProperty: function (value, bReadOnly, bWriteOnly, fnChangeCondition) {
        var self = this;

        if (bob.utils.isUndefinedOrNull(fnChangeCondition)) {
            fnChangeCondition = function (oldValue, newValue) { return true; };
        }
        else if (!bob.utils.isFunction(fnChangeCondition)) {
            throw new Error('Wrong argument: fnChangeCondition');
        }

        bob.prop.Property.apply(self, [value, bReadOnly, bWriteOnly]);

        //fire this event every time any setter is called.
        this.change = new bob.event.Event();
        var onChange = self.change.get_caller();

        var get_value = bob.utils.isFunction(self.get_value)
            ? self.get_value
            : self.get_getter(true);

        //change notifications.
        var set_value = bob.utils.isFunction(self.set_value)
            ? self.set_value
            : self.get_setter(true);

        //this is a wrapper around setter so that we intercept calls to set.
        var setValueAnyhow = function (value) {
            var oldValue = get_value();
            if (fnChangeCondition(oldValue, value)) {
                try {
                    set_value(value);
                }
                finally {
                    onChange.apply(self, [value]);
                }
            }

        };

        if (bob.utils.isFunction(self.set_value)) {
            self.set_value = function (value) {
                setValueAnyhow(value);
            };
        }
        else if (bob.utils.isFunction(self.get_setter)) {
            var get_setter = self.get_setter;
            self.get_setter = function () {
                get_setter.apply(self, arguments);
                return setValueAnyhow;
            };
        }
    },


    //v3
    namedNotifierProperty: function (objThis, sName, value, bReadOnly, bWriteOnly, fnChangeCondition) {
        var notifierProperty = new bob.prop.event.NotifierProperty(value, bReadOnly, bWriteOnly, fnChangeCondition);
        bob.event.namedEvent(true, objThis, sName, notifierProperty.change);

        return bob.prop.namedProp(true, objThis, sName, notifierProperty);
    },

    //v3
    Observer: function (value, bReadOnly, bWriteOnly) {
        var self = this;

        var fnChangeCondition = function (oldValue, newValue) {
            return !bob.utils.equals(oldValue, newValue);
        };

        bob.prop.event.NotifierProperty.apply(self, [value, bReadOnly, bWriteOnly, fnChangeCondition]);
    },

    //v3
    namedObserver: function (objThis, sName, value, bReadOnly, bWriteOnly) {
        var fnChangeCondition = function (oldValue, newValue) {
            return !bob.utils.equals(oldValue, newValue);
        };

        return bob.prop.event.namedNotifierProperty(objThis, sName, value, bReadOnly, bWriteOnly, fnChangeCondition);
    }

});
